/*
 * FormaAleta.cpp
 *
 *  Created on: 24/10/2013
 *      Author: ezequiel
 */

#include "FormaAleta.h"
#define CANT_PUNTOS 60
FormaAleta::FormaAleta() {
	 this->planta_vertex_buffer_size = CANT_PUNTOS/3 *CANT_PUNTOS/3 * 3  ;
		    this->planta_vertex_buffer = new GLfloat[this->planta_vertex_buffer_size];
		    this->planta_texture_buffer = new GLfloat[this->planta_vertex_buffer_size * 2 / 3 ];
		    //
	//	    if (this->planta_normal_buffer != NULL)
	//	    {
	//	        delete this->planta_normal_buffer;
	//	    }
		    this->planta_normal_buffer_size = CANT_PUNTOS/3 *CANT_PUNTOS/3 * 3 ;
		    this->planta_normal_buffer = new GLfloat[this->planta_normal_buffer_size];

	//	    if (this->planta_index_buffer != NULL)
	//	    {
	//	        delete this->planta_index_buffer;
	//	    }
		    this->planta_index_buffer_size = 760;
		    this->planta_index_buffer = new GLuint[this->planta_index_buffer_size];
		this->pControl1 = 0;
		this->pControl2 = 0;
		this->crearForma();
}

FormaAleta::~FormaAleta() {
	delete this->planta_vertex_buffer;
	delete this->planta_normal_buffer;
	delete this->planta_index_buffer;
}

void FormaAleta::render(GLuint handle, glm::mat4* matModelo) {
//	this->crearForma();
	this->renderMatrix(handle, &proyeccion);
//			    glm::mat3 normal_matrix = glm::mat3 ( 1.0f );
	glm::vec3 light_intensity = glm::vec3(0.4f, 0.2f, 0.2f);
//	glm::vec4 light_position = glm::vec4(0.0f, 1.0f, 0.0f, 0.0f);
	 glm::vec4 light_position = glm::vec4( 0.0f, 1.0f, 0.0f, 0.0f );
//			    glm::vec3 light_intensity = glm::vec3( 1.0f, 1.0f, 1.0f );
	glm::vec3 La = glm::vec3(0.5f, 0.2f, 0.1f);
	glm::vec3 Ld = glm::vec3(1.0f, 1.0f, 1.0f);
	glm::vec3 Ls = glm::vec3(0.1f, 1.0f, 0.6f);
	glm::vec3 Ka = glm::vec3(0.2f, 0.2f, 0.2f);;
	glm::vec3 Kd = glm::vec3(0.8f, 0.8f, 0.8f);
	glm::vec3 Ks = glm::vec3(0.5f, 0.0f, 0.0f);
	float Shininess = 0.5;
//
				// Light Intensity
								GLuint location_light_intensity = glGetUniformLocation(handle,
									"LightIntensity");

								if(location_light_intensity >= 0)
									glUniform3fv( location_light_intensity, 1, &light_intensity[0]);
								else
									cout << "PROBLEM " << endl;
								// Light Position
								GLuint location_light_position = glGetUniformLocation(handle,
									"LightPosition");

								if(location_light_position >= 0)
									glUniform4fv( location_light_position, 1, &light_position[0]);

								// La
								GLuint location_la = glGetUniformLocation(
									handle, "La");

								if(location_la >= 0)
									glUniform3fv( location_la, 1, &La[0]);

								// Ld
								GLuint location_ld = glGetUniformLocation(
									handle, "Ld");

								if(location_ld >= 0)
									glUniform3fv( location_ld, 1, &Ld[0]);

								// Ls
								GLuint location_ls = glGetUniformLocation(
									handle, "Ls");

								if(location_ls >= 0)
									glUniform3fv( location_ls, 1, &Ls[0]);


								// Ka
								GLuint location_ka = glGetUniformLocation(
									handle, "Ka");

								if(location_ka >= 0)
									glUniform3fv( location_ka, 1, &Ka[0]);

								// Kd
								GLuint location_kd = glGetUniformLocation(
									handle, "Kd");

								if(location_kd >= 0)
									glUniform3fv( location_kd, 1, &Kd[0]);

								// Ks
								GLuint location_ks = glGetUniformLocation(
									handle, "Ks");

								if(location_ks >= 0)
									glUniform3fv( location_ks, 1, &Ks[0]);


								// Shininess
								GLfloat location_shininess = glGetUniformLocation(handle,
									"Shininess");

								if(location_shininess >= 0)
									glUniform1f(location_shininess, Shininess);


			    // Bind Normal MAtrix
								// Normal Matrix
				glm::mat3 normal_matrix = glm::transpose(glm::inverse(glm::mat3(*matModelo)));
			    GLuint location_normal_matrix = glGetUniformLocation(handle, "NormalMatrix");
			    if( location_normal_matrix >= 0 )
				{
			        glUniformMatrix3fv( location_normal_matrix, 1, GL_FALSE, &normal_matrix[0][0]);
				}

			    // Bind Model Matrix
			    GLuint location_model_matrix = glGetUniformLocation( handle, "ModelMatrix");
			    if( location_model_matrix >= 0 )
				{
					glUniformMatrix4fv( location_model_matrix, 1, GL_FALSE,&((*matModelo)[0][0]));
				}



			    float lightRadius = 2.0f;
				GLuint radioLuz = glGetUniformLocation(handle, "lightRadius");
							    if( radioLuz >= 0 )
								{
							    	glUniform1f( radioLuz, lightRadius);
								}

			    glActiveTexture(GL_TEXTURE0);
			        glEnable(GL_TEXTURE_2D);
			        int loc = glGetUniformLocation(handle, "Tex1");
			        glUniform1i(loc, 0);
			        glBindTexture(GL_TEXTURE_2D, this->textureid);

			    				    if(this->textureNormalId != 0){
			    				    glActiveTexture(GL_TEXTURE1);
			    				    glEnable(GL_TEXTURE_2D);
			    				    int loc1 = glGetUniformLocation(handle, "NormalMapTex");
			    				    glUniform1i(loc1, 1);
			    				    glBindTexture(GL_TEXTURE_2D, this->textureNormalId);  }

			    				    if(this->textureReflexionId != 0){
			    				    	glActiveTexture (GL_TEXTURE2);
			    				    int loc2 = glGetUniformLocation(handle, "ReflexionMap");
			    				    glUniform1i(loc2, 2);
			    				//    glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
			    				//    glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
			    				//    glEnable(GL_TEXTURE_GEN_S);
			    				//    glEnable(GL_TEXTURE_GEN_T);
			    				    	glBindTexture (GL_TEXTURE_2D, this->textureReflexionId); }

			    glEnableClientState(GL_VERTEX_ARRAY);
				glEnableClientState(GL_NORMAL_ARRAY);
				glEnableClientState(GL_TEXTURE_COORD_ARRAY);
//				glEnableClientState(GL_COLOR_ARRAY);
				glVertexPointer(3, GL_FLOAT, 0, planta_vertex_buffer);
				glNormalPointer(GL_FLOAT, 0, planta_normal_buffer);
				glTexCoordPointer(2, GL_FLOAT, 0, planta_texture_buffer);
			    glDrawElements(GL_TRIANGLE_STRIP, this->planta_index_buffer_size, GL_UNSIGNED_INT, this->planta_index_buffer);
			    glDisableClientState(GL_TEXTURE_COORD_ARRAY);

			    glDisableClientState(GL_VERTEX_ARRAY);
			    glDisableClientState(GL_NORMAL_ARRAY);
}

void FormaAleta::indexarPuntos() {
	int malla[20][20];

			        int e = 0;
			        for(int m = 0; m < 20; m++)
			                for(int n = 0; n < 20; n++)
			                        malla[m][n] = e++;


			        int sentido = 1;
			        int k = 0;

			        for(int i=0; i < (19); i++)
			        {
			                if(sentido == 1)
			                {
			                        for(int j=0; j <= (19); j++) {
			                                this->planta_index_buffer[k++] = malla[i][j];
			                                this->planta_index_buffer[k++] = malla[i+1][j];
			                        }

			                        sentido = -1;
			                }
			                else if(sentido == -1)
			                {
			                        for(int j=(19); j >= 0; j--) {
			                                this->planta_index_buffer[k++] = malla[i][j];
			                                this->planta_index_buffer[k++] = malla[i+1][j];
			                        }

			                        sentido = 1;
			                }
			        }



}

void FormaAleta::calcularNormales() {

//	glm::vec3 vecResult;
//	glm::vec3 vec1;
//	glm::vec3 vec2;
//
//for (int k = 0 ; k < CANT_PUNTOS - 1 ; k++){
//	for (int i = k * CANT_PUNTOS * 3 ; i < k * CANT_PUNTOS * 3 + CANT_PUNTOS * 3 ; i = i +3 )
//	{
//		vec1.x = aleta_vertex_buffer[i] - aleta_vertex_buffer[i+3*CANT_PUNTOS];
//		vec1.y = aleta_vertex_buffer[i+1] - aleta_vertex_buffer[i+3*CANT_PUNTOS+1];
//		vec1.z = aleta_vertex_buffer[i+2] - aleta_vertex_buffer[i+3*CANT_PUNTOS+2];
//		vec2.x = aleta_vertex_buffer[i] - aleta_vertex_buffer[i+3];
//		vec2.y = aleta_vertex_buffer[i+1] -aleta_vertex_buffer[i+4];
//		vec2.z = aleta_vertex_buffer[i+2] -aleta_vertex_buffer[i+5];
//		vecResult = calcularNormal(vec1, vec2);
//		aleta_normal_buffer[i] = vecResult.x;
//		aleta_normal_buffer[i+1] = vecResult.y;
//		aleta_normal_buffer[i+2] = vecResult.z;
//
//	}
//}
//
//for (int k = 0 ; k < CANT_PUNTOS - 1 ; k++){
//
//}

}

glm::vec3 FormaAleta::calcularNormal(glm::vec3 vec1, glm::vec3 vec2) {
	glm::vec3 retorno;
	retorno.x = vec1.y * vec2.z - vec1.z * vec2.y;
		retorno.y = vec1.z * vec2.x - vec1.x * vec2.z;
		retorno.z =vec1.x * vec2.y - vec1.y * vec2.x;
	return retorno;
}

void FormaAleta::render(GLuint handle) {
}

void FormaAleta::crearForma() {
	//////////////// vector de direccion //////////////
		    vector<glm::vec3> vector;
		    	glm::vec3 vect = glm::vec3(-10.0f, 0.0f , 0.0f);
		    	vector.push_back(vect);
		    	vect = glm::vec3(-5.0f, 0.0f , 0.0f);
		    	vector.push_back(vect);
		    	vect = glm::vec3(5.0f, 0.0f , 0.0f);
		    	vector.push_back(vect);
		    	vect = glm::vec3(10.0f, 0.0f , 0.0f);
		    	vector.push_back(vect);
		    	CurvaBessier* curvaBes = new CurvaBessier(vector,CANT_PUNTOS / 3 - 1 );
	////////////// vector z /////////////

		    	std::vector<glm::vec3> otrov;
		    	vect = glm::vec3(0.0f, 0.0f , 5.0f);
		    	otrov.push_back(vect);
		    	vect = glm::vec3(0.0f, pControl1 , 10.0f);
		    	otrov.push_back(vect);
		    	vect = glm::vec3(0.0f, pControl1, 15.0f);
		    	otrov.push_back(vect);
		    	vect = glm::vec3(0.0f, pControl1 , 20.0f);
		    	otrov.push_back(vect);
	//	       	vect = glm::vec3(18.0f, 0.0f , 0.0f);
	//	    	   otrov.push_back(vect);
		    	CurvaBessier* curvaBes2 = new CurvaBessier(otrov,CANT_PUNTOS / 3 - 1 );
	//	    	CurvaSpline* curvaBes2 = new CurvaSpline(otrov, CANT_PUNTOS / 3 - 1);

		    	this->alturaPlanta = CANT_PUNTOS / 3 - 1;
	////////////// curva grosor ////////////////


		    	std::vector<glm::vec3> vecGrosor;
		    	vect = glm::vec3(5.0f, 0.0f , 0.0f);
		    	vecGrosor.push_back(vect);
		    	vect = glm::vec3(10.0f, 0.37f , 0.0f);
		    	vecGrosor.push_back(vect);
		    	vect = glm::vec3(15.0f, 0.43f , 0.0f);
		    	vecGrosor.push_back(vect);
		    	vect = glm::vec3(20.0f, 0.0f , 0.0f);
		    	vecGrosor.push_back(vect);
		    	CurvaBessier* curvaGrosor = new CurvaBessier(vecGrosor,CANT_PUNTOS / 3 - 1 );





		    	/////////////// declaracion de vectores ////////////

		    	otrov = curvaBes2->obtenerPuntos();
		    	vector = curvaBes->obtenerPuntos();
		    	vecGrosor = curvaGrosor->obtenerPuntos();
		    	delete curvaBes2;
		    	delete curvaBes;
		    	delete curvaGrosor;

		    	 float pasoU = 0;
		    	float pasoV = 0.0;
		    	int p = 0;

		    	int j ;
		    	for (int k = 0 ; k < CANT_PUNTOS / 3 ; k++){
		    	j = 0;
		    	pasoU = 0.0;
		    	pasoV = pasoV + 0.05;
		    	for(int i = k * CANT_PUNTOS;i < (k+1) * CANT_PUNTOS; i = i + 3)
		    	{
		    		this->planta_vertex_buffer[i] = (vector[j].x  + otrov[k].x) * vecGrosor[k].y  ;
		    		this->planta_vertex_buffer[i+1] = ( vector[j].y + otrov[k].y )   ;
		    		this->planta_vertex_buffer[i+2] = (vector[j].z  + otrov[k].z) ;
		    		this->planta_texture_buffer[p] = pasoU;
		    		p++;
		    		 this->planta_texture_buffer[p] = pasoV;
		    		p++;
		    		pasoU = pasoU + 0.05 ;
		    		this->planta_normal_buffer[i] = 0.1f;
		    		this->planta_normal_buffer[i+1] = 0.1f;
		    		this->planta_normal_buffer[i+2] = 0.1f;
	//	    		this->planta_index_buffer[i] = j + k* CANT_PUNTOS/3;
	//	    		this->planta_index_buffer[i+1] = j + k* CANT_PUNTOS/3 ;
	//	    		this->planta_index_buffer[i+2] = j + k* CANT_PUNTOS/3;
		    		j++;

		    	}
		    	}
	//	    	this->calcularNormales();
		    	this->indexarPuntos();
	//	    	this->indexar();
}
